/**
 * N*M的格子，放置[0...N*M-1]的数。
 * 从左上走到右下的路径，只能向下或者向右，问路径的mex最大是多少
 * 首先0肯定能在路径上，将整个区域分成4份，其中2份合法，2份非法
 * 如果1在合法区域中，又将该区域分为4份，
 * 如果2在合法区域中，……
 * 如此可以用什么数据结构？
 * 可以做二分。看mex能否达为x，其含义是[0...x-1]都必须在路径上
 * 初始令limit = (0, 0)
 * 从上到下从左到右扫描每一格，如果该格的权值在[0...x-1]
 *     如果该格不在limit的右下，直接返回false
 *     更新limit
 * 能出循环返回true
 * 检查一遍的时间是O(NM)，整个时间是O(NMlogNM)
 */
#include <bits/stdc++.h>
using namespace std;

#include <bits/extc++.h>
using namespace __gnu_pbds;

using Real = double;
using llt = long long;
using pii = pair<int, int>;
using vi = vector<int>;

int N, M;
vector<vi> A;
vector<pii> Pos;

bool check(int val){
    int x = 0, y = 0;
    for(int i=0;i<N;++i)for(int j=0;j<M;++j){
        if(A[i][j] >= val) continue;
        if(i < x or j < y) return false;
        x = i; y = j;
    }
    return true;
}

int proc(){
    int left = 0, right = N * M, mid;
    do{
        mid = (left + right) >> 1;
        if(check(mid)) left = mid + 1;
        else right = mid - 1;
    }while(left <= right);
    return right;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(0);
    int nofakse = 1;
    cin >> nofakse;
    while(nofakse--){
        cin >> N >> M;
        A.assign(N, vi(M, 0));
        for(auto & a : A)for(auto & i : a)cin>>i;
        cout << proc() << endl;
    }
    return 0;
}